﻿using DotPowerJob.Enum;
using DotPowerJob.Requests;
using DotPowerJob.Responses;
using Flurl;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using DotPowerJob.Models;
using Flurl.Http;
using Microsoft.Extensions.Logging;
using System.Runtime.CompilerServices;

namespace DotPowerJob
{
    public class InstanceTask : IDisposable
    {
        private readonly PowerJobConfig _jobConfig;
        private readonly ILogger _logger;
        public InstanceTask(PowerJobConfig jobConfig, ILogger logger)
        {
            _jobConfig = jobConfig;
            this.ReportInstanceStatus();
            _logger = logger;
        }

        /// <summary>
        /// powerjob请求参数
        /// </summary>
        public ServerScheduleJobRequest request { get; set; }

        /// <summary>
        /// 实例状态
        /// </summary>
        public InstanceStatus Status { get; set; }

        public CancellationTokenSource ExectorToken { get; set; } = new CancellationTokenSource();

        private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
        private Task reportInstanceStatusTask = null;

        /// <summary>
        /// 上报实例状态
        /// </summary>
        public void ReportInstanceStatus()
        {
            if (this._cancellationTokenSource == null)
            {
                return;
            }
            var ct = this._cancellationTokenSource.Token;
            this.reportInstanceStatusTask = Task.Factory.StartNew(async () =>
            {
                while (!ct.IsCancellationRequested)// && this.Status == InstanceStatus.RUNNING)
                {
                    this._logger.LogInformation($"report instance ({this.request.InstanceId}) status");
                    await this.SendRequest();
                    await Task.Delay(TimeSpan.FromSeconds(10), ct);
                }
            }, this._cancellationTokenSource.Token);
        }

        /// <summary>
        /// 完成任务
        /// </summary>
        /// <returns></returns>
        public async Task ComplateTask(InstanceStatus status)
        {
            this._cancellationTokenSource?.Cancel();
            this._cancellationTokenSource?.Dispose();
            this._cancellationTokenSource = null;
            this.Status = status;
            await this.reportInstanceStatusTask;
            await this.SendRequest();
        }

        /// <summary>
        /// 停止任务
        /// </summary>
        /// <returns></returns>
        public async Task StopTask()
        {
            this._cancellationTokenSource?.Cancel();
            this._cancellationTokenSource?.Dispose();
            this._cancellationTokenSource = null;
            
            this.Status = InstanceStatus.STOPPED;

            this.ExectorToken.Cancel();

            await this.reportInstanceStatusTask;
            await this.SendRequest();
        }

        private async Task SendRequest()
        {
            var request = new TaskTrackerReportInstanceStatusRequest()
            {
                JobId = this.request.JobId,
                InstanceId = this.request.InstanceId,
                ReportTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                SourceAddress = this._jobConfig.ClientAddress,
                InstanceStatus = this.Status
            };
            var jsonStr = JsonConvert.SerializeObject(request, new JsonSerializerSettings()
            {
                ContractResolver = new CamelCasePropertyNamesContractResolver()
            });
            HttpContent content = new StringContent(jsonStr);

            var response = await PowerJobCache.ServerAddress.AppendPathSegment("/server/reportInstanceStatus")
                .WithHeader("content-type", "application/json")
                .PostAsync(content)
                .ReceiveJson<PowerJobResponse>();
        }

        public async void Dispose()
        {
            this._cancellationTokenSource?.Dispose();
            this._cancellationTokenSource = null;
            this.Status = InstanceStatus.CANCELED;
            await this.reportInstanceStatusTask;
        }
    }
}
